<!--通用下拉列表组件 20230113 botao.yu  *输入项的查询参数默认为condition，在界面初始化时如果有值，会向后台传入当前值，键名为selectedVal-->
<!--@param value  *必输，下拉绑定的v-model:value字段 单选时为字符串，多选时支持'|'分隔的字符串和数组 -->
<!--@param columns *必输， 展示列配置 包含value label  width-->
<!--@param selectOption  *必输，拉输入框的配置项，label和value代表显示值和实际值-->
<!--@param data 指定的下拉表格数据，指定data为数据来源时，做前端的查询和模糊匹配(目前只筛选selectOption中指定的两个参数:value为匹配，label为模糊匹配)-->
<!--@param url  下拉表格的数据来源URL，URL和DATA二选一传入，URL优先级高,在控件初始化时会向后台传入键为selectVal的value属性值，防止无所选项导致的默认值翻译失败 -->
<!--@param multiple 是否多选，默认为单选，单选时返回v-model:value的为单值，多选返回的是数组-->
<!--@param refId 下拉选择框的refId 需要获取内部参数时颗自行配置-->
<!--@param tWidth 下拉面板的宽度 默认350-->
<!--@param selectChange 下拉change方法，参数为所有选中行的rows结果集-->
<!--@param queryParam 额外的查询条件JSON，一般为分页参数或标志 默认值为{pageSize:60 , pageNum:1}-->
<!-- 使用样例
<selectTable
    v-model:value="queryParams.testID"
    url="/tradeCombox/counterPartyCombox"
    :multiple="true"
    :data="table.data"
    tWidth="900"
    :selectChange="selectChg"
    :queryParam = "{pageSize:60 , pageNum:1}"
    :columns="[
     { label: '物料编号', width: '100px', value: 'partyId' },
     { label: '物料名称', width: '149px', value: 'partyName' }
    ]"
    :selectOption="{ label: 'partyName', value: 'partyId' }"
/>
-->
<template>
  <div :id="selectId"  :style="{width: '100%'}">
  <el-select
      v-model="$data.modelVal"
      v-bind="{ ...$attrs }"
      :style="{width: '100%'}"
      @change="handselect"
      @click.native="deptogglePanel($event)"
      :ref="refId"
      clearable remote="false"
      :multiple="$props.multiple==true||$props.multiple=='true'"
      collapse-tags-tooltip
      collapse-tags >
    <el-option
        v-for="(item,index) in totalData"
        :key="String(item[selectOption.value])"
        :label="String(item[selectOption.label])"
        :value="String(item[selectOption.value])">
    </el-option>
  </el-select>
  <div v-if="showTree" class="treeDiv"  id="tableListDiv" :style="{width: `${tableWidth}px`}" >
    <el-input
              v-model="$data.ssVal" clearable="true"
              :style="{width: '250px'}"
              :prefix-icon="Search"
               >
      <template #prepend>
        <span  > 搜索</span>
      </template>
    </el-input>
    <el-table
        max-height="250"
        :multiple="$props.multiple==true||$props.multiple=='true'"
        @select="handleSelectClick"
        highlight-current-row="true"
        stripe="true"
        @selection-change="handleChange"
        @row-click="rowClickFun"
        :row-style="rowStyleFun"
        ref="selectTableCommIdRef"
        :data="pageDataList" border
        @select-all="selectAll">
      <el-table-column type="selection"  v-if="$props.multiple==true||$props.multiple=='true'" width="45" align="center" />
      <el-table-column type="radio" width="45" :label="单选"  align="center"  class-name="radioStyle" v-else>
        <template #default="scope">
          <el-radio v-model="radioVal" :label="scope.$index + 1"  @click.native.prevent="radioChange(scope.row, scope.$index + 1)"></el-radio>
        </template>
      </el-table-column>
      <el-table-column
          v-for="(item, index) in columns"
          :key="index"
          header-align="center"
          :prop="item.value"
          :label="item.label"
          :align="item.align==undefined?'center':item.align"
          :width="item.width==undefined?'150px':item.width"
          :show-overflow-tooltip="true">
      </el-table-column>
    </el-table>
  </div>
  </div>
</template>
<script>
import lsh from 'lodash';
import request from '@/utils/request'

export default {
  expose:['selectionGroupRow'],
  props: {
    /**下拉选择框的refId 需要获取内部参数时颗自行配置*/
    refId:{
      required:false,
      type:String,
      default: () => {
        return "selectTableCommRef";
      }
    },
    /**下拉绑定的v-model:value字段*/
    value:{
      type: [String, Number, Array]
    },
    /**是否多选，默认为单选，单选时返回v-model的为单值，多选返回的是数组*/
    multiple:{
      type: Boolean,
      default: () => {
        return true
      }
    },
    /**URL和DATA二选一传入，URL优先级高*/
    url:{
      type:String,
      default: () => {
        return null
      }
    },
    /**直接赋予表格数据集，在URL传入时无效*/
    data:{
      type:Array,
      default: () => {
        return []
      }
    },
    /**展示列配置 包含value label  width */
    columns:{
      type:Array,
      default: () => {
        return []
      }
    },
    /**下拉面板的宽度 */
    tWidth:{
      type:Number,
      default: () => {
        return 350
      }
    },
    /**下拉change方法，参数所有选中行的rows结果集*/
    selectChange:{
      type:Function,
    },
    /**下拉输入框的配置项，label和value代表显示值和实际值*/
    selectOption:{
      type:Object,
      default: () => {
        return { label: 'name', value: 'code' }
      }
    },
    /**额外的查询条件，一般为分页参数或标志*/
    queryParam:{
      type:Object,
      default: () => {
        return {pageSize:10 , pageNum:1}
      }
    }
  },
  data() {
    return {
      timer: '',//防抖定时器
      ssVal: '',
      selectId:this.guid2(),
      refId:this.$props.refId,
      radioVal:'',
      modelVal:'',
      selectionGroupRow:[],
      arr: [],
      totalData: [], //原始的所有的数据
      selectSortDataList: [], // 按选择结果排序整理后的数据
      pageDataList:[],//最后实际当页的数据
      showTree: false,
      columns: this.$props.columns,
      tableWidth:this.$props.tWidth,
      multipleSelection: [],
      selectOption:this.$props.selectOption,
      queryParam:this.$props.queryParam
    }
  },

  created() {
    //增加焦点监听，移出时关闭table
    document.addEventListener('mousedown', (e) => {
      let typePanel = document.getElementById(this.selectId);
      if(typePanel){
        if (!typePanel.contains(e.target)){
          this.tableHide();
        }
      }
    })
    //数据初始化
    this.init();
  },
  watch: {
    ssVal: {
      handler:lsh.debounce(async function(){
        this.handinput();
      },300),
      immediate: true
    }
  },
  methods: {
    init() {
      this.$nextTick(() => {
        this.arr = [];
        this.ssVal='';
        this.multipleSelection = [];
      }).then(()=>{
        if(this.url!=undefined&&this.url!=''&&this.url!=null) {
          //有url时
          let params=lsh.cloneDeep(this.queryParam);
          request({
            url: this.url,
            method: 'get',
            params: lsh.assign(params,{'condition': this.ssVal,'selectedVal':this.$props.value})
          }).then((response) => {
            if (response.result != undefined) {
              this.totalData = response.result
            } else if (response.rows != undefined) {
              this.totalData = response.rows
            } else if (response.msg != undefined) {
              this.totalData = response.msg
            } else if (response.list != undefined) {
              this.totalData = response.list
            } else if (response.length >= 0) {
              this.totalData = response
            }
            this.selectSortDataList=this.totalData;
            this.dealInitData();
          })
        }else{
          this.totalData =  this.$props.data;
          this.selectSortDataList = this.$props.data;
          this.dealInitData();
        }
      }).catch((error) => {
        console.log(error);
      });
    },
    /**初始化数据处理*/
    dealInitData(){
      this.modelVal = []
      this.multipleSelection =[];
      //初始化值，其他操作都在tableShow中统一处理
      if (this.multiple!= true &&this.multiple!='true') {
        this.modelVal=this.$props.value;
      }else{
        if(this.$props.value!=null&&this.$props.value&&this.$props.value!=''){
          this.modelVal=Array.isArray(this.$props.value)?this.$props.value:this.$props.value.split(",");
        }
      }
    },
    /**隐藏select自带的下拉框*/
    isShowSelect(val) {
      this.$refs[this.refId].blur();
    },
    /** 点击input 阻止冒泡 控制table显示隐藏*/
    deptogglePanel(event) {
      this.isShowSelect();//隐藏select本来的下拉框
      event || (event = window.event)
      event.stopPropagation ? event.stopPropagation() : (event.cancelBubble = true)
      this.showTree ? this.tableHide() : this.tableShow()
    },
    /**每次打开处理选中值 */
    tableShow() {
      //每次打开查询条件为空
      if(this.modelVal!=null&&this.modelVal!=''&&this.modelVal!=undefined){
        //默认值 直接为数组或者'|'分隔的字符串
        let defaultVal=Array.isArray(this.modelVal)?this.modelVal:this.modelVal.split("|");
        let idStr=this.$props.selectOption.value;
        let copyTotalData=lsh.cloneDeep(this.totalData);
        defaultVal.forEach(item=> {
          this.multipleSelection.push(lsh.find(copyTotalData,function(obj){
            let keyStr=String(obj[idStr])
            return keyStr==String(item);
          }));
          lsh.remove(copyTotalData, function(n) {
            let keyStr=String(n[idStr])
            return keyStr==String(item);
          });
        })
        lsh.remove(this.multipleSelection, function(n) {
          return n===undefined;
        });
        this.multipleSelection=lsh.uniqWith(this.multipleSelection, lsh.isEqual);
        this.selectSortDataList=lsh.concat(this.multipleSelection,copyTotalData)
      }else{
        this.selectSortDataList=this.totalData;
      }
      this.dealPageData(this.selectSortDataList);
      //打开面板并选中数据
      this.showTree = true
      this.selectionGroupRow=lsh.cloneDeep(this.multipleSelection);
      this.rowMultipleChecked(this.multipleSelection);
    },
    //隐藏表格
    tableHide() {
      this.showTree = false
      this.$emit('update:value', this.modelVal)
      if (Object.prototype.toString.call(this.$props.selectChange) === '[object Function]') {
        this.$props.selectChange(lsh.cloneDeep(this.multipleSelection));
      }
    },
    radioChange (row, index)  {
    },
    //选中赋予index
    rowStyleFun({row, rowIndex}) {
      Object.defineProperty(row, 'rowIndex', { //给每一行添加不可枚举属性rowIndex来标识当前行
        value: rowIndex,
        writable: true,
        enumerable: false
      })
    },
    /**处理行点击和赋值*/
    rowClickFun(row, column, event) {
      let idStr=this.selectOption.value;
      this.showTree = true
      let refsElTable = this.$refs.selectTableCommIdRef; // 获取表格对象
      let multiple = this.$props.multiple;
      let findRow = this.selectionGroupRow.find(c => c[idStr] == row[idStr]);
      if (findRow) {
        refsElTable.toggleRowSelection(row, false);
        refsElTable.setCurrentRow();
        this.lsh.remove(this.selectionGroupRow, function (o) {
          return String(o[idStr]) === String(row[idStr]);
        });
        this.multipleSelection=lsh.cloneDeep(this.selectionGroupRow);
        if (multiple!= true &&multiple!='true') {
          this.radioVal='';
        }
        //全部重新赋值
        this.arr=[];
        for (let i in this.multipleSelection) {
          this.arr.push(String(this.multipleSelection[i][idStr]))
        }
        if (this.$props.multiple === true || this.$props.multiple === 'true') {
          this.modelVal = this.arr;//select赋值
        }else{
          this.modelVal = this.arr[0];//select赋值
        }
        return;
      }
      if (multiple === true || multiple === 'true') {
        this.selectionGroupRow.push(row);
        this.multipleSelection.push(row);
        refsElTable.setCurrentRow(row);
        refsElTable.toggleRowSelection(row); // 调用选中行方法
      } else {
        this.radioVal=row.rowIndex+1;
        refsElTable.clearSelection();
        this.selectionGroupRow = [row];
        this.multipleSelection = [row];
        refsElTable.setCurrentRow(row);
        refsElTable.toggleRowSelection(row);
        this.tableHide();
      }

     },
    /**行checkbox选中change方法*/
    handleChange(rows) {
      let idStr=this.selectOption.value;
      this.arr=[];
      for (let i in rows) {
        this.arr.push(String(rows[i][idStr]))
      }
      if (this.$props.multiple === true || this.$props.multiple === 'true') {
        this.modelVal = this.arr;//select赋值
      }else{
        this.modelVal = this.arr[0];//select赋值
      }
    },
    // 多选
    handleSelectClick(data) {
      this.showTree = true
    },
    //全选
    selectAll(data) {
      this.showTree = true
    },
    /**多选赋值 默认值赋值*/
    rowMultipleChecked(multipleSelection) {
      if (multipleSelection != null) {
        for (let j = 0; j < multipleSelection.length; j++) {
          for (let i = 0; i < this.selectSortDataList.length; i++) {
            if (String(multipleSelection[j][this.selectOption.value]) == String(this.selectSortDataList[i][this.selectOption.value])) {//如果在后端传来的值中id存在则选中多选框
              this.$nextTick(() => {//必写
                let refsElTable = this.$refs.selectTableCommIdRef;
                if (refsElTable != undefined) {
                  if (this.$props.multiple === true || this.$props.multiple === 'true') {
                  } else {
                    this.radioVal=i+1;
                  }
                  refsElTable.toggleRowSelection(this.selectSortDataList[i], true);
                }
              })
            }
          }
        }
      }
    },
    /**处理分页数据*/
    dealPageData(pageList){
      this.pageDataList=pageList;
    },
    /**下拉框清除回调*/
    handselect(value) {
      let data = [];
      let arr = [];
      let idStr=this.selectOption.value;
      if (value.length > 0) {//删除multipleSelection（选中的所有值）中的value
        for (let j = 0; j < value.length; j++) {
          data.push(lsh.filter(this.multipleSelection,function(item){
            return String(item[idStr])==String(value[j]);
          })[0]);
        }
        this.multipleSelection = data
      } else {
        this.multipleSelection = [];
        data = [];
      }
      for (let s in data) {
        arr.push(data[s][idStr])
      }
      if (arr != null) {//需要判断那些值需要取消选中
        if(this.$refs.selectTableCommIdRef!=undefined){
          for (let i = 0; i < this.selectSortDataList.length; i++) {
            if (arr.indexOf(this.selectSortDataList[i].id) == -1) {
              this.$refs.selectTableCommIdRef.toggleRowSelection(this.selectSortDataList[i], false);
            }
          }
        }
      }
      this.$emit('update:value', this.modelVal)
      if (Object.prototype.toString.call(this.$props.selectChange) === '[object Function]') {
        this.$props.selectChange(lsh.cloneDeep(this.multipleSelection));
      }
    },
    /**搜索方法 有URL时传入后台查询最新结果，无URL时返回前端搜索结果*/
    handinput() {
      if(this.url!=undefined&&this.url!=''&&this.url!=null){
        //有url时
        return request({
          url: this.url,
          method: 'get',
          params: lsh.assign(this.queryParam,{'condition': this.$data.ssVal})
        }).then((response) => {
          if (response.result != undefined) {
            this.totalData = response.result
          } else if (response.rows != undefined) {
            this.totalData = response.rows
          } else if (response.msg != undefined) {
            this.totalData = response.msg
          } else if (response.list != undefined) {
            this.totalData = response.list
          } else if (response.length >= 0) {
            this.totalData = response
          }
          this.selectSortDataList=this.totalData;
          this.selectSortDataList=this.concatSelectData(this.multipleSelection,this.selectSortDataList);
        }).then(()=>{
          this.dealPageData(this.selectSortDataList);
          this.rowMultipleChecked(this.multipleSelection);
        })
      }else{
        //无url时,取data数据
        if(this.totalData!=null&&this.totalData.length>0){
          let tmpTotalData=lsh.cloneDeep(this.totalData);
          let option=this.selectOption;
          let queryVal=this.ssVal;
          //暂时只筛选 selectOption中的主要配置，后续如果要筛选全部columns的参数，需要修改
          this.selectSortDataList=lsh.filter(tmpTotalData,function(data){
            return String(data[option.value])==String(queryVal)||data[option.label].indexOf(queryVal)!=-1;
          })
          this.concatSelectData(this.multipleSelection,this.selectSortDataList);
          this.dealPageData(this.selectSortDataList);
          this.rowMultipleChecked(this.multipleSelection);
        }
      }

    },
    concatSelectData(selectData,pageData){
      let idStr=this.$props.selectOption.value;
      let copySortDataList=lsh.cloneDeep(pageData);
      selectData.forEach(item=> {
        lsh.remove(copySortDataList, function (n) {
          let keyStr = String(n[idStr])
          return keyStr == String(item[idStr]);
        });
      })
      return lsh.concat(selectData,copySortDataList);
    },
    //生成组件唯一id
    guid2() {
      function S4() {
        return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);
      }
      return (S4() + S4()   + S4() +   S4() +  S4() +   S4() + S4() + S4());
    }
  },
}
</script>

<script setup>
import {getCurrentInstance, watch} from 'vue'
const {proxy} = getCurrentInstance()

watch(() => proxy.$attrs.data, (nv, ov) => {
  proxy.selectionGroupRow = [];
}, {deep: true})
</script>
<style lang="scss">
// 单选样式
.radioStyle {
  .el-radio {
    .el-radio__label {
      display: none;
    }
    &:focus:not(.is-focus):not(:active):not(.is-disabled) .el-radio__inner {
      box-shadow: none;
    }
  }
  :deep(tbody) {
    .el-table__row {
      cursor: pointer;
    }
  }
}

</style>
<style scoped>


.treeDiv {
  position: absolute;
  top: 25px;
  left: -1px;
  z-index: 16777271 !important;
  width: 300px;
  overflow: auto;
  max-height: 280px;
  border-radius: 6px;
  background: #FFFFFF;
}


.treeDiv .el-table {
  font-size: 14px;
}

.treeDiv .el-table /deep/ td {
  padding: 4px 0;
}

#selecTable .el-select {
  width: 100%;
}

#selecTable .el-input {
  width: 100%;
}


</style>
